﻿using LitJson;
using System;
using System.Collections.Generic;

namespace TableCore.Plugin
{
    public class InvalidFormulaInputException : Exception
    {
        public InvalidFormulaInputException() : base("不合法的公式格式") { }

        public InvalidFormulaInputException(GTFile.Content content, string cell, string formula) 
            : base(string.Format("不合法的公式\"{0}\"\n {1}#{2}(单元格: {3})", formula, content.File, content.Cmodel.ClassName, cell)) { }

    }

    public class FormulaFormatter : IGenFormatter, IGenCmdInitializer//, IBeforeGenFormatter
    {
        FormulaFactory mFormulaFac;
        //Dictionary<string, string> mAlias;
        //Dictionary<string, int> mValues;
        //HashSet<string> mNames;
        //Regex mAliasRegex = new Regex(@"(?<=#alias#) .+", RegexOptions.IgnoreCase);
        //Regex mValueRegex = new Regex(@"(?<=#value#) .+", RegexOptions.IgnoreCase);
        //Regex mEvaluateRegex = new Regex(@"(?<= +)[\w\u4e00-\u9fa5]+=\w+");
        //Dictionary<int, FormulaOperator> mFormulaOperators;
        //AtomFormula mAtomFormula;
        //Regex mAliasTarget = new Regex(@"^[\w\u4e00-\u9fa5]+(?=_\d+$)");
        public FormulaFactory Factory => mFormulaFac;

        class LogicCompilier : IReferenceFormulaCompilier, IFunctionFormulaCompilier
        {
            bool IReferenceFormulaCompilier.CompileOutput(ICompilingFormulaState rt, IFormulaSource input)
            {
                return true;
            }

            bool IFunctionFormulaCompilier.CompileOutput(ICompilingFormulaState rt, IFormulaSource input, IFormulaSource args)
            {
                return true;
            }

        }

        class BinCompilier: IBinaryFormulaCompilier
        {
            bool IBinaryFormulaCompilier.CompileOutput(ICompilingFormulaState rt, IFormulaSource input, IFormulaSource left, IFormulaSource right)
            {
                //if (input.Keyword == "in" || input.Keyword == "out")
                //    return right.Id == '(' && left.Id != '(';
                //else
                    return true;
            }
        }

        public FormulaFormatter()
        {
            mFormulaFac = new FormulaFactory(true, false);

            // predefind value
            //mFormulaFac.SetPredefinedValue("Famous", new FamousValue(false));
            //mFormulaFac.SetPredefinedValue("FamousLv", new FamousValue(true));
            // formulas
            IFormulaOutput compilier = new LogicCompilier();
            mFormulaFac.SetFormulaOutput(compilier);
            compilier = new BinCompilier();
            //mFormulaFac.SetFormulaOutput("and", new AndLogic(null, null));
            //mFormulaFac.SetFormulaOutput("or", new OrLogic(null, null));
            //mFormulaFac.SetFormulaOutput("not", new NotLogic(null));
            mFormulaFac.CreateFormula(">", (int)EFormulaOperatePriority.MathBinary - 10, compilier);
            mFormulaFac.CreateFormula("<", (int)EFormulaOperatePriority.MathBinary - 10, compilier);
            mFormulaFac.CreateFormula(">=", (int)EFormulaOperatePriority.MathBinary - 10, compilier);
            mFormulaFac.CreateFormula("<=", (int)EFormulaOperatePriority.MathBinary - 10, compilier);
            mFormulaFac.CreateFormula("==", (int)EFormulaOperatePriority.MathBinary - 10, compilier);
            mFormulaFac.CreateFormula("!=", (int)EFormulaOperatePriority.MathBinary - 10, compilier);
            mFormulaFac.AliasFormula("!=", "！=");

            mFormulaFac.CreateFormula("in", (int)EFormulaOperatePriority.MathBinary - 10, compilier);
            mFormulaFac.CreateFormula("out", (int)EFormulaOperatePriority.MathBinary - 10, compilier);
            mFormulaFac.CreateFormula(":", (int)EFormulaOperatePriority.Function - 10, compilier);
            mFormulaFac.AliasFormula(":", "：");

        }

        public void Init(GTType type, Dictionary<string, string> args, string content)
        {
            mFormulaFac.ParseCmd(content);
        }

        public IExportData ExportData(GTFile.Content content, string data, string cellName, string comment)
        {
            return null;
        }

        //public void BeforeFormat(int currentCol, object[] row)
        //{
        //    var len = row == null ? 0 : row.Length;
        //    var data = currentCol < len ? Utils.GetString(row[currentCol]) : null;
        //    if (string.IsNullOrEmpty(data) || StringUtil.EqualIgnoreCase(data, "none") || data.IndexOf('_') != -1)
        //        return;
        //    var id = currentCol + 1 < len ? Utils.GetString(row[currentCol + 1]) : null;
        //    if (string.IsNullOrEmpty(id))
        //        return;
        //    //string str;
        //    //if (!mAlias.TryGetValue(data, out str) && mNames.Contains(data))
        //    //    str = data;
        //    //if(!string.IsNullOrEmpty(str))
        //    //{
        //    row[currentCol] = StringUtil.Concat(data, "_", id);
        //    //}
        //}

        public JsonData Format(GTFile.Content content, string data, string cellName, string comment)
        {
            if (string.IsNullOrEmpty(data) || StringUtil.EqualIgnoreCase(data, "none"))
                return null;
            try
            {
                mFormulaFac.GetReadyForCompilingFormula();
                var formula = mFormulaFac.CompileFormula(data);
                return data;
            }
            catch
            {
                throw new InvalidFormulaInputException(content, cellName, data);
            }
        }

        public bool IsValid(string data)
        {
            return true;
        }

    }
}
